const captcha = require("svg-captcha");
const Utils = require("../utils");
const Redis = require("../utils/Redis");
const Email = require("../utils/Email");
const SMS = require("./SMS");

class Code {
  /**
   * 获取图形验证码
   * @param {string} client_uuid // 客户端唯一标识
   * @returns {Promise<{data:string;uuid:string}>}
   */
  static getCode(client_uuid) {
    return new Promise(async (resolve, reject) => {
      if (!client_uuid) {
        reject({ code: 400, message: "客户端唯一标识不能为空" });
        return;
      }
      // 生成图形验证码
      const option = {
        size: 4, // 字母数量
        ignoreChars: "0oO1ilI", // 不适用字符串
        noise: 5, // 干扰线
        width: 100, // 宽
        height: 30, // 高
        fontSize: 26, // 字体大小
      };
      try {
        const svg = captcha.create(option);
        // 生成uuid
        const uuid = Utils.createUUID();
        // 保存到redis
        await Redis.set(`code-${uuid}`, JSON.stringify({ code: svg.text, client_uuid }), "EX", 600);
        resolve({ data: svg.data, uuid });
      } catch (error) {
        reject(error);
      }
    });
  }

  /**
   * 校验图形验证码
   * @param {string} client_uuid // 客户端唯一标识
   * @param {string} uuid // 服务端生成的uuid
   * @param {string} code
   * @returns {Promise<boolean>}
   */
  static checkCode(client_uuid, uuid, code) {
    return new Promise(async (resolve, reject) => {
      if (!client_uuid) {
        reject({ code: 400, message: "客户端唯一标识不能为空" });
        return;
      }
      if (!uuid) {
        reject({ code: 400, message: "uuid不能为空" });
        return;
      }
      if (!code) {
        reject({ code: 400, message: "验证码不能为空" });
        return;
      }
      try {
        let bool = false;
        // 获取万能验证码
        const adminOverrideCode = Utils.getConfig().adminOverrideCode;
        // 如果设置了万能验证码，先和万能验证码比较
        if (adminOverrideCode && adminOverrideCode === code) {
          bool = true;
        } else {
          // 如果万能验证码不通过,则校验redis中的验证码
          let data = await Redis.get(`code-${uuid}`);
          if (!data) {
            reject({ code: 400, message: "验证码已过期" });
            return;
          }
          data = JSON.parse(data);

          bool = client_uuid === data.client_uuid && code && data.code.toLowerCase() === code.toLowerCase();
        }
        // 删除redis中的验证码
        await Redis.del(`code-${uuid}`);
        resolve(bool);
      } catch (error) {
        reject(error);
      }
    });
  }

  /**
   * 发送邮件验证码
   * @param {string} client_uuid // 客户端唯一标识
   * @param {string} email 邮箱
   * @param {string} baseKey // redis中的key
   * @returns {Promise<string>}
   */
  static sendEmailCode(client_uuid, email, baseKey = "email-code") {
    return new Promise(async (resolve, reject) => {
      if (!client_uuid) {
        reject({ code: 400, message: "客户端唯一标识不能为空" });
        return;
      }
      if (!email) {
        reject({ code: 400, message: "收件人邮箱不能为空" });
        return;
      }
      try {
        // 生成验证码
        const code = Code.createCode();
        // 保存到redis
        await Redis.set(`${baseKey}-${email}`, JSON.stringify({ code, client_uuid }), "EX", 900);
        // 发送邮件
        await Email.send(
          email,
          "验证码",
          `
            <h3 style="color:#333333;">您正在进行邮箱验证操作</h3>
            <div style="color:#333333;display:flex;align-items:center;">
              <h3>您的验证码是：</h3>
              <h1 style="color:#3478f6;background-color:#333333;padding:3px 10px;">
                ${code}
              </h1>
            </div>
            <p style="color:#ff5555;">验证码有效期15分钟</p>
          `
        );
        resolve();
      } catch (error) {
        reject(error);
      }
    });
  }

  /**
   * 校验邮箱验证码
   * @param {string} client_uuid // 客户端唯一标识
   * @param {string} email 邮箱
   * @param {string} code 验证码
   * @returns {Promise<boolean>}
   */
  static checkEmailCode(client_uuid, email, code, baseKey = "email-code") {
    return new Promise(async (resolve, reject) => {
      if (!client_uuid) {
        reject({ code: 400, message: "客户端唯一标识不能为空" });
        return;
      }
      if (!Email.isEmail(email)) {
        reject({ code: 400, message: "收件人邮箱格式错误" });
        return;
      }
      if (!code) {
        reject({ code: 400, message: "验证码不能为空" });
        return;
      }

      try {
        let bool = false;
        // 获取万能验证码
        const adminOverrideCode = Utils.getConfig().adminOverrideCode;
        // 如果设置了万能验证码，先和万能验证码比较
        if (adminOverrideCode && adminOverrideCode === code) {
          bool = true;
        } else {
          // 如果万能验证码不通过,则校验redis中的验证码
          let data = await Redis.get(`${baseKey}-${email}`);
          if (!data) {
            reject({ code: 400, message: "验证码已过期" });
            return;
          }
          data = JSON.parse(data);
          bool = data.client_uuid === client_uuid && code && data.code.toLowerCase() === code.toLowerCase();
        }
        // 如果验证成功，删除redis中的验证码
        if (bool) await Redis.del(`${baseKey}-${email}`);
        resolve(bool);
      } catch (error) {
        reject(error);
      }
    });
  }

  /**
   * 发送短信验证码
   */
  static sendPhoneCode(phone_number, client_ip) {
    return new Promise(async (resolve, reject) => {
      if (!phone_number) {
        reject({ code: 400, message: "手机号码不能为空" });
        return;
      }
      try {
        // 调用腾讯云发送短信方法
        const result = await SMS.sendTencentSMS(phone_number, client_ip);
        resolve(result);
      } catch (error) {
        reject(error);
      }
    });
  }

  /**
   * 校验短信验证码
   */
  static checkPhoneCode(phone_number, uuid, code) {
    return new Promise(async (resolve, reject) => {
      if (!SMS.isPhone(phone_number)) {
        reject({ code: 400, message: "手机号码格式不正确" });
        return;
      }
      try {
        let bool = false;
        // 获取万能验证码
        const adminOverrideCode = Utils.getConfig().adminOverrideCode;
        // 如果设置了万能验证码，先和万能验证码比较
        if (adminOverrideCode && adminOverrideCode === code) {
          bool = true;
        } else {
          bool = await SMS.checkSMS(phone_number, uuid, code);
        }
        resolve(bool);
      } catch (error) {
        reject(error);
      }
    });
  }

  /**
   * 生成验证码
   * @returns {string}
   */
  static createCode() {
    const code = [];
    for (let i = 0; i < 6; i++) {
      code.push(Utils.strs[Math.floor(Math.random() * Utils.strs.length)]);
    }
    return code.join("").toLocaleUpperCase();
  }
}

module.exports = Code;
